Indicative Functions. Writing indicative functions soon… 您所在的位置:网站首页 indicative function Indicative Functions. Writing indicative functions soon…

Indicative Functions. Writing indicative functions soon…

2024-06-15 09:55| 来源: 网络整理| 查看: 265

The Rules

Let us now define the aforementioned rules for functions in JavaScript and similar languages.

Const

Function handles exported from an imported member of a dependency

Function definitions in nested function scope

import * as dependency from “./dependency”;...export const foo = dependency.foo; // camel case generallyexport const SomeType = dependency.SomeType; // pascal case for type...class Foo{ bar() { // constant function def in nested scope const handler = () => {...} ... }}

Re-exporting provides a unified facade that abstracts nested dependencies away from the calling code using your module.

It also saves on potentially having to import both this module and the dependency separately in the calling code.

Whilst const data is often named by PascalCase, only do so if the function is a type constructor, resorting to camelCase otherwise.

Note, TypeScript (and similar) provide a type keyword that should be preferred for exporting type constructors:

export type SomeType = dependency.SomeType;Let

Functions defined in nested function scope that will be initialised as soon as possible, and treated as immutable thereafter

Store functions in a let inside nested function scopes when you absolutely cannot initialise the function definition at the time of declaration (in a constant manner).

function addLoginHandler(user){ let handler; ... if(!!user) { handler = () => this.logout(); } else { handler = () => this.login(); } button.addEventListener("click", handler);}

The distance between declaration and initialisation should be as small as possible.

The eventual assignment should use a lambda, instead of a nested usage of the function keyword (see Function Keyword).

Note also that anonymous functions are inherently hard to test in isolation.

Instance Methods

Functions defined at class scope

Functions that will only be invoked directly on the instance that it belongs to

The only valid context in which to reference this

class Example{ ... instanceMethod() { ... this.navigator.push({ ... }); // valid usage of 'this.' }}

Whether defined inside a class statement, or on the underlying prototypes directly, a common pitfall in JavaScript is to assume that the relationship between incident object and instance method is concrete.

Sadly there is little that keeps these two pieces of data together, and that is often a cause of bugs.

For example, passing handles to instance methods as first order parameters removes this membership association:

loginButton.addEventListener("click", this.handleLogin); // NO!

Consequently, any reference to this inside handleLogin is liable to act unpredictability when that callback fires.

Thus never call, apply or pass instance methods as first order functions. Their invocation must be fully qualified:

const example = new Example();…example.instanceMethod(); // fully qualified using incident objectLambdas

To preserve the relationship between instance method and incident object, in lieu of bind

Function definitions assigned to a let datum in nested function scope

Function definitions assigned to properties inside object literals

return { ... foo : () => { ... } // lambdas for object literal properties}

A lambda can serve the same purpose as bind, whilst being more readable at a glance.

It signals intent to divorce a function from it’s own concept of this, and thus is perfect for preserving the relationship between an instance method and it’s own this handle.

form.addEventListener(“submit”, () => this.checkout());

One might note that a truly bound function cannot be rebound subsequently.

This is an inconsequential fact since passing an instance method as a first order citizen is a violation of the rules herein.

Hence it should never need to be bound, or rebound in any case.

Function Keyword

Functions defined immediately at file scope

The function keyword should appear at the outermost scope of a file, as the first lexical token on a line, preceded only by the export token where appropriate.

function isDiff(item1, item2){ return JSON.stringify(item1) !== JSON.stringify(item2); }

This follows the hierarchical structure whereby only the following exist at file scope (in order):

importsexported constant dataconstant dataclass definitionsfunction definitions via the function keyword

Any function at file scope should always be declared as a straightforward assignment, i.e. you should encapsulate any dynamic logic in nested function scopes.

Note, if you are defining a variadic function in nested function scope (and must therefore have access to unknown arguments) you may use the function keyword, but consider it an anti-pattern:

function parentScope(){ function variadic() { // usage of arguments } ...}.apply(…) | .call(…)

Incident function must not be an instance method

Supplied thisArg must be null Function body must not contains references to this

Given the rules governing the use of instance methods, usage of call and apply mechanisms should be predictably scant.

Both can be useful for invoking a static, variadic function:

function print(){ ...}...function printUsers(users){ print.apply(null, users); // thisArg set to null}

A frequent violation of this rule however is to set the thisArg of an event handler to point to the incident object on which the event is raised.

This is an anti-pattern, and the preferred approach utilises closures:

input.addEventListener(“change”, () => { const { value } = input; // closed over 'input' reference ...});


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有